package com.javasm.commons.interceptors;

import com.alibaba.fastjson.JSON;
import com.javasm.commons.enums.E;
import com.javasm.commons.exception.MvcException;
import com.javasm.entity.JINXIAOEntity.SysUser;
import com.javasm.util.JWTUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//springmvc拦截器
@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // 1.在LoginInterceptor类中定义一个ThreadLocal类型的静态变量来存储用户标识
    // 2. 在拦截器中设置用户标识 在你的拦截器的preHandle方法中（或其他适当的位置），你可以设置当前线程的用户标识。
    //3. 在需要的地方获取用户标识 在应用程序的其他部分，当你需要获取当前用户的标识时，你可以从ThreadLocal变量中获取。
    //    String currentUserId = LoginInterceptor.currentUser.get();
    // 4. 清理ThreadLocal变量  重要的是要确保在不再需要用户标识时清理ThreadLocal变量，以避免内存泄漏。你可以在拦截器的afterCompletion方法中执行此操作。
    private static final ThreadLocal<SysUser> currentUser = new ThreadLocal<>();

    public static void set(SysUser u){
        currentUser.set(u);
    }

    public static SysUser getLoginUser(){
        return currentUser.get();
    }

//    @Override
//    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//        System.out.println("loginInterceptor");
//        return true;
//    }

    //前拦截
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //非白名单的接口请求进入拦截器
        String method = request.getMethod();
        if(method.equals("OPTIONS")){  //针对复杂请求的预检请求放行 不检查session会话  预检请求直接返回，不会进入拦截器了
            return true;
        }
        //检验客户端所有的请求携带的token是否失效
        String token = request.getHeader("admin_token");
        if(token==null||token.equals(""))throw new MvcException(E.NO_LOGIN);

        //解析登录令牌并返回用户信息
        Claims claims = JWTUtil.parseLoginToken(token);
        if(claims==null)throw new MvcException(E.NO_LOGIN);

        //根据token获取用户标识信息
        String uphone = JWTUtil.getUid(claims);

        //读取redis缓存的用户信息
        ValueOperations<String, Object> stringObjectValueOperations = redisTemplate.opsForValue();//redis类型操作对象（不指定类型 object）

        String s = (String) stringObjectValueOperations.get("sysUser:" + uphone);
        if(s==null) throw new MvcException(E.NO_LOGIN);
        SysUser sysUser = JSON.parseObject(s, SysUser.class);

        //2.把用户标识放在ThreadLocal线程变量中
        currentUser.set(sysUser);

        //刷新token 失效时间范围内，请求接口刷新token，避免直接回退登录页面
        String newToken= JWTUtil.generateLoginToken(uphone);
        response.addHeader("admin_token",newToken);

        return true;
    }

    //返回
//    @Override
//    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//        System.out.println("postHandle");
//    }
//
//    //最终拦截
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
        //4. 清理当前线程的用户标识
        currentUser.remove();
    }
}
